package net.lab0.fractal.fractals.mandelbrot;


import java.util.ArrayList;

import net.lab0.fractal.classes.RenderingCoordinates;


public class MultithreadedMandelbrotFractal
extends BasicMandelbrotFractal
{
	private ArrayList<MandelbrotComputationThread>	computationThreads;
	private ArrayList<Float>						progresses;
	private Integer									finishedComputations;
	
	public MultithreadedMandelbrotFractal(RenderingCoordinates viewCoordinates, long maxIteration, float progressUpdateInterval, long timeUpdateInterval,
	int threads)
	{
		super(viewCoordinates, maxIteration, progressUpdateInterval, timeUpdateInterval);
		this.computationThreads = new ArrayList<MandelbrotComputationThread>(threads);
		for (int i = 0; i < threads; ++i)
		{
			MandelbrotComputationThread thread = new MandelbrotComputationThread(this);
			computationThreads.add(thread);
			thread.start();
		}
		progresses = new ArrayList<Float>(threads);
		for (int i = 0; i < threads; ++i)
		{
			progresses.add(new Float(0f));
		}
		finishedComputations = new Integer(0);
	}
	
	@Override
	protected void computationBlock(int compH, int compW, double xStep, double yStep, double xCenter, double yCenter, double viewportWidth,
	double viewportHeight)
	{
		synchronized (finishedComputations)
		{
			finishedComputations = 0;
		}
		int slices = computationThreads.size();
		for (int slice = 0; slice < slices; ++slice)
		{
			MandelbrotComputationThread thread = computationThreads.get(slice);
			thread.setCompH(compH);
			thread.setCompW(compW);
			thread.setxStep(xStep);
			thread.setyStep(yStep);
			thread.setxCenter(xCenter);
			thread.setyCenter(yCenter);
			thread.setViewportWidth(viewportWidth);
			thread.setViewportHeight(viewportHeight);
			thread.setSlice(slice);
			thread.setSlices(slices);
			thread.setGo(true);
		}
		
		while (finishedComputations < slices)
		{
			try
			{
				Thread.sleep(250);
			}
			catch (InterruptedException e)
			{
			}
		}
	}
	
	public void setProgress(float progress, MandelbrotComputationThread mandelbrotComputationThread)
	{
		progresses.set(mandelbrotComputationThread.getSlice(), progress / mandelbrotComputationThread.getSlices());
		float total = 0;
		for (Float f : progresses)
		{
			total += f;
		}
		super.setProgress(total);
	}
	
	public void notifyFinished(MandelbrotComputationThread thread)
	{
		synchronized (finishedComputations)
		{
			finishedComputations++;
		}
	}
	
	protected void pauseTest()
	{
		super.pauseTest();
	}
}
